package gui;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;

import app.AppInterface;

@SuppressWarnings("serial")
public class GuiSync extends JPanel {

	private final boolean DEBUG = false;

	private AppInterface app;
	private GuiObserver mainGui;
	private JPanel cardPanel;
	private JTextField localIPLabel, remoteIPLabel;
	private JTextField ipTextField, folderTextField, secondFolderTextField;
	private JButton folderButton, secondFolderButton, syncButton, cancelButton;
	private JCheckBox localSyncCheckBox, startListenCheckBox;
	private Timer timer = null;
	private JFileChooser dirChooser;
	public SyncListener syncListener; // TODO �ndra till annan l�sning
	public CancelListener cancelListener; // TODO �ndra till annan l�sning

	public GuiSync(AppInterface app, GuiObserver mainGui) {

		this.app = app;
		this.mainGui = mainGui;
		setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));


		JPanel ipTextPanel = new JPanel();

		localIPLabel = new JTextField(app.getLocalIp());
		localIPLabel.setToolTipText("Click to get another local IP address");
		localIPLabel.setEditable(false);
		localIPLabel.setBorder(new TitledBorder("Local IP"));
		localIPLabel.addMouseListener(new LocalIPListener());

		remoteIPLabel = new JTextField(app.getLastConectionIP());
		remoteIPLabel.setToolTipText("This is the IP of the computer that you where last connected to");
		remoteIPLabel.setEditable(false);
		remoteIPLabel.setBorder(new TitledBorder("Last Con."));

		ipTextPanel.add(localIPLabel);
		ipTextPanel.add(Box.createRigidArea(new Dimension(10, 0)));
		ipTextPanel.add(remoteIPLabel);


		JPanel folderPanel = new JPanel();
		folderPanel.setBorder(new TitledBorder(new EmptyBorder(0,0,0,0), "Folder:", TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION));
		folderTextField = new JTextField(20); // 25 is better in windows //TODO set global font and size
		FolderListener folderListener = new FolderListener();
		folderTextField.addActionListener(folderListener);
		folderTextField.addFocusListener(folderListener);
		folderButton = new JButton("Browse");
		folderButton.setMnemonic('B');
		folderButton.addActionListener(folderListener);
		folderPanel.add(folderTextField);
		folderPanel.add(folderButton);


		// secondFolderPanel & ipPanel are both used in the cardPanel
		JPanel secondFolderPanel = new JPanel();
		secondFolderPanel.setBorder(new TitledBorder(new EmptyBorder(0,0,0,0), "2:nd Folder:", TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION));
		secondFolderTextField = new JTextField(20); // 25 is better in windows //TODO set global font and size
		SecondFolderListener secondFolderListener = new SecondFolderListener();
		secondFolderTextField.addActionListener(secondFolderListener);
		secondFolderTextField.addFocusListener(secondFolderListener);
		secondFolderButton = new JButton("Browse");
		secondFolderButton.setMnemonic('r');
		secondFolderButton.addActionListener(secondFolderListener);
		secondFolderPanel.add(secondFolderTextField);
		secondFolderPanel.add(secondFolderButton);

		JPanel ipPanel = new JPanel();
		ipPanel.setBorder(new TitledBorder(new EmptyBorder(0,0,0,0), "Remote IP:", TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION));
		ipTextField = new JTextField(10);
		IPTextFieldListener ipTextFieldListener = new IPTextFieldListener();
		ipTextField.addActionListener(ipTextFieldListener);
		ipTextField.addFocusListener(ipTextFieldListener);
		ipPanel.add(ipTextField);

		// Create the panel that contains the "cards".
		cardPanel = new JPanel();
		cardPanel.setLayout(new CardLayout());
		cardPanel.add(ipPanel, "ipPanel");
		cardPanel.add(secondFolderPanel, "secondFolderPanel");
		cardPanel.setMaximumSize(new Dimension(300, 20));


		JPanel checkBoxPanel = new JPanel();
		checkBoxPanel.setLayout(new BoxLayout(checkBoxPanel, BoxLayout.Y_AXIS));
		checkBoxPanel.setAlignmentX((float)0.5);
		localSyncCheckBox = new JCheckBox(" Local Sync");
		localSyncCheckBox.setToolTipText("Check this box to be able to sync locally without having to use an ip address");
		localSyncCheckBox.setMnemonic('o');
		LocalSyncListener localSyncListener = new LocalSyncListener();
		localSyncCheckBox.addItemListener(localSyncListener);
		checkBoxPanel.add(localSyncCheckBox);

		startListenCheckBox = new JCheckBox(" Start Listen");
		startListenCheckBox.setToolTipText("Check this box to make the program able to communicate with other computers");
		startListenCheckBox.setMnemonic('L');
		StartListenListener startListenListener = new StartListenListener();
		startListenCheckBox.addItemListener(startListenListener);
		checkBoxPanel.add(Box.createRigidArea(new Dimension(0, 5)));
		checkBoxPanel.add(startListenCheckBox);


		JPanel syncPanel = new JPanel();
		syncButton = new JButton("Sync");
		syncButton.setToolTipText("You have to press \"Start Listen\" or \"Local Sync\" first");
		syncButton.setMnemonic('S');
		syncButton.setEnabled(false);
		syncListener = new SyncListener();
		syncButton.addActionListener(syncListener);
		syncPanel.add(syncButton);

		cancelButton = new JButton("Cancel");
		cancelButton.setToolTipText("Abort Sync");
		cancelButton.setMnemonic('C');
		cancelButton.setEnabled(false);
		cancelListener = new CancelListener();
		cancelButton.addActionListener(cancelListener);
		syncPanel.add(cancelButton);


		add(Box.createRigidArea(new Dimension(0, 5)));
		add(ipTextPanel);
		add(Box.createRigidArea(new Dimension(0, 5)));
		add(folderPanel);
		add(Box.createRigidArea(new Dimension(0, 2)));
		add(cardPanel);
		add(Box.createRigidArea(new Dimension(0, 30)));
		add(checkBoxPanel);
		add(Box.createVerticalGlue());
		add(syncPanel);
		add(Box.createRigidArea(new Dimension(0, 5)));
	}

	// Is called to initiated the sync tab
	public void setGuiSync() {

		if(DEBUG) System.out.println("Init gui sync");

		folderTextField.setText(app.getDirectory().getPath());
		secondFolderTextField.setText(app.getSecondDir().getPath());
		ipTextField.setText(app.getIPAddress());
		localSyncCheckBox.setSelected(app.getLocalSync());
		startListenCheckBox.setSelected(app.getStartListen());
	}

	public void startAutoSync() {
		//TODO m�ste finnas en ip-address eller en annan map kan fixa en if sats
		timer = new Timer(app.getAutoSyncDelay(), syncListener);
		timer.start();
	}

	public void stopAutoSync() {

		if(timer != null && timer.isRunning()) {
			timer.stop();
		}
	}

	private class LocalIPListener extends MouseAdapter {

		public void mouseClicked(MouseEvent event) {

			class NextLocalIP extends Thread { // Start a thread to not halt the whole program
				public void run() {
					String nextLocalIP = app.getNextLocalIP(localIPLabel.getText());
					localIPLabel.setText("Querying...");
					localIPLabel.setSize(localIPLabel.getPreferredSize());
					localIPLabel.setText(nextLocalIP);
					localIPLabel.setSize(localIPLabel.getPreferredSize());
				}

			}
			(new NextLocalIP()).start();
		}
	}

	private class IPTextFieldListener implements ActionListener, FocusListener {

		public void setIP() {
			String ipAddress = ipTextField.getText().trim();
			boolean change = false;
			if(!app.getIPAddress().equals(ipAddress)) {
				change = true;
			}
			app.setIPAddress(ipAddress);
			if(change) { // Remove oldRemoteFileList if it exist and if the user chooses to do so
				removeOldRemoteFileLists();
			}
		}

		public void actionPerformed(ActionEvent event) {
			setIP();
		}

		public void focusLost(FocusEvent event) {
			setIP();
		}

		public void focusGained(FocusEvent event) {	
		}
	}

	private class FolderListener implements ActionListener, FocusListener {

		// boolean to make sure that setFolder() is only called once form either actionPerformed() or focusLost()
		boolean folderCheck = false;
		
		// Asks to remove the oldRemoteFileList before changing the folder
		private void changeFolder(File currentDirectory) {
			if( !currentDirectory.getAbsolutePath().equals( app.getDirectory().getAbsolutePath() ) ) {
				removeOldRemoteFileLists();
			}
			app.setDirectory( currentDirectory );
		}

		private void setFolder() {

			File currentDirectory = new File(folderTextField.getText());
			if( currentDirectory.isDirectory() ) {
				changeFolder( currentDirectory );
			}
			else {
				JOptionPane.showMessageDialog(null, "The folder: \"" + currentDirectory + "\"\n" +
						"does not exist!",
						"Sync IT - No folder", JOptionPane.INFORMATION_MESSAGE);
				folderTextField.setText(app.getDirectory().getAbsolutePath());
			}
		}

		public void actionPerformed(ActionEvent event) {

			if( event.getSource().equals(folderButton) ) {

				dirChooser = new JFileChooser();
				dirChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
				int value = dirChooser.showDialog(null, "Select Folder");

				if(value == JFileChooser.APPROVE_OPTION) {
					File currentDirectory = dirChooser.getSelectedFile();
					folderTextField.setText(currentDirectory.getPath());
					changeFolder(currentDirectory);
				}
			}
			else if( event.getSource().equals(folderTextField) ) {

				folderCheck = true;
				setFolder();
				folderCheck = false;
			}
		}

		public void focusLost(FocusEvent event) {

			if(!folderCheck) {
				setFolder();
			}
		}

		public void focusGained(FocusEvent event) {
		}
	}

	private class SecondFolderListener implements ActionListener, FocusListener {

		// boolean to make sure that setFolder() is only called once form either actionPerformed() or focusLost()
		boolean folderCheck = false;
		
		// Asks to remove the oldRemoteFileList before changing the folder
		private void changeFolder(File currentDirectory) {
			if( !currentDirectory.getAbsolutePath().equals( app.getSecondDir().getAbsolutePath() ) ) {
				removeOldRemoteFileLists();
			}
			app.setSecondDir( currentDirectory );
		}

		private void setFolder() {

			File currentDirectory = new File(secondFolderTextField.getText());
			if( currentDirectory.isDirectory() ) {
				changeFolder( currentDirectory );
			}
			else {
				JOptionPane.showMessageDialog(null, "The folder: \"" + currentDirectory + "\"\n" +
						"does not exist!",
						"Sync IT - No folder", JOptionPane.INFORMATION_MESSAGE);
				secondFolderTextField.setText(app.getSecondDir().getAbsolutePath());
			}
		}

		public void actionPerformed(ActionEvent event) {

			if( event.getSource().equals(secondFolderButton) ) {

				dirChooser = new JFileChooser();
				dirChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
				int value = dirChooser.showDialog(null, "Select Folder");

				if(value == JFileChooser.APPROVE_OPTION) {
					File currentDirectory = dirChooser.getSelectedFile();
					secondFolderTextField.setText(currentDirectory.getPath());
					changeFolder(currentDirectory);
				}
			}
			else if( event.getSource().equals(secondFolderTextField) ) {

				folderCheck = true;
				setFolder();
				folderCheck = false;
			}
		}

		public void focusLost(FocusEvent event) {

			if(!folderCheck) {
				setFolder();
			}
		}

		public void focusGained(FocusEvent event) {
		}
	}

	// Help funktion
	// called by LocalSyncListener and StartListenListener
	private void enableSyncButtons(boolean show) {

		if(show) {
			syncButton.setToolTipText("Press to start Sync");
			syncButton.setEnabled(true);
			cancelButton.setEnabled(true);
		}
		else {
			if (!localSyncCheckBox.isSelected() && !startListenCheckBox.isSelected()) {
				syncButton.setToolTipText("You have to press \"Start Listen\" or \"Local Sync\" first");
				syncButton.setEnabled(false);
				cancelButton.setEnabled(false);
			}
		}
	}

	private class LocalSyncListener implements ItemListener {

		public void itemStateChanged(ItemEvent event) {

			if(localSyncCheckBox.isSelected() != app.getLocalSync()) { // Remove oldRemoteFileList if it exist and if the user chooses to do so
				removeOldRemoteFileLists();
			}

			CardLayout cl = (CardLayout)(cardPanel.getLayout());
			if(localSyncCheckBox.isSelected()) {
				cl.show(cardPanel, "secondFolderPanel");
				app.setLocalSync(true);
				mainGui.setLocalSync(true);
				enableSyncButtons(true);
			}
			else {
				cl.show(cardPanel, "ipPanel");
				app.setLocalSync(false);
				mainGui.setLocalSync(false);
				enableSyncButtons(false);
			}
		}
	}

	private class StartListenListener implements ItemListener {

		public void itemStateChanged(ItemEvent event) {

			if(startListenCheckBox.isSelected()) {
				if( (new File(folderTextField.getText())).isDirectory() ) {
					app.setStartListen(true);
					if(localSyncCheckBox.isEnabled()) { // Is to make shore that the syncButten is not enabled while a localSync is running
						mainGui.enableOtherGuiComponents(true);
						enableSyncButtons(true);
					}
					else { // Special case to enable disable the listen port field
						mainGui.enableListenPortField(false);
					}
				}
				else {
					startListenCheckBox.setSelected(false);
					JOptionPane.showMessageDialog(null, "You have to choose a valid folder first!", 
							"Sync IT - No folder", JOptionPane.INFORMATION_MESSAGE);
				}

			}
			else {
				app.setStartListen(false);
				mainGui.enableOtherGuiComponents(false);
				enableSyncButtons(false);
			}
		}
	}

	public class SyncListener implements ActionListener {

		public void actionPerformed(ActionEvent event) {

			// Starts a local sync //
			if( localSyncCheckBox.isSelected() ) {
				// Checks if the selected directory's are valid
				if(new File(folderTextField.getText()).isDirectory() && new File(secondFolderTextField.getText()).isDirectory()) {
					app.saveConfig();
					app.startSync();
				}
				else {
					JOptionPane.showMessageDialog(null, "Folder: \"" + folderTextField.getText() + "\" or\n" +
							"Folder: \"" + secondFolderTextField.getText() + "\"\n" +
							"does not exist!",
							"Sync IT - No folder", JOptionPane.INFORMATION_MESSAGE);
				}
			}
			// Starts a remote sync //
			else if( startListenCheckBox.isSelected() ) {
				// Checks if the selected directory's are valid
				if(new File(folderTextField.getText()).isDirectory()) {
					app.saveConfig();
					app.startSync();
				}
				else {
					JOptionPane.showMessageDialog(null, "The folder: \"" + folderTextField.getText() + "\"\n" +
							"does not exist!",
							"Sync IT - No folder", JOptionPane.INFORMATION_MESSAGE);
				}
			}

		}
	}

	private class CancelListener implements ActionListener {

		public void actionPerformed(ActionEvent event) {
			app.cancel();
		}
	}



	// Methods that comes from GuiChangeObserver, sent through the mainGui //

	// Enables and disables components when a sync is initiated or finished
	// is called through an observer
	public void enableGuiComponents(boolean show) {

		folderTextField.setEnabled(show);
		folderButton.setEnabled(show);
		secondFolderTextField.setEnabled(show);
		secondFolderButton.setEnabled(show);
		ipTextField.setEnabled(show);
		localSyncCheckBox.setEnabled(show);
		// enable/disable syncButton
		if (show && (localSyncCheckBox.isSelected() || startListenCheckBox.isSelected())) {
			syncButton.setEnabled(true);
		}
		else {
			syncButton.setEnabled(false);
		}

		// Start/Stop the timer
		if(!show) { // stop timer
			if(timer != null && timer.isRunning()) {
				timer.stop();
			}
		}
		else { // start timer
			if(app.getAutoSync()) {
				timer.restart();
			}
		}
	}


	// Methods that comes from LogToGuiObserver, sent through the mainGui //

	public void connectionStatusChanged(String message) {

		if(message.startsWith("Connected to: ") || message.startsWith("Incomming connection: ")) {
			String lastConectionIP = message.split(":")[1].trim();
			app.setLastConectionIP(lastConectionIP);
			app.saveConfig();
			remoteIPLabel.setText(lastConectionIP);
		}
		else if(message.startsWith("Connection: Local sync through port: ")) {
			String lastConectionIP = "Local Host";
			app.setLastConectionIP(lastConectionIP);
			app.saveConfig();
			remoteIPLabel.setText(lastConectionIP);
		}
	}

	public void connectionStatusWarning(String message) {
		// Uncheck startListen if it was not possible to listen to the port
		if(message.startsWith("Could not listen on port:")) {
			startListenCheckBox.setSelected(false);
		}
	}

	// Remove oldRemoteFileList if it exist and if the user chooses to do so
	private void removeOldRemoteFileLists() {
		if(app.doesOldRemoteFileListsExist()) {
			int ans = JOptionPane.showConfirmDialog(null,
					"Would you like remove your sync history?",
					"Remove history",
					JOptionPane.YES_NO_OPTION);
			if(ans == JOptionPane.YES_OPTION) {
				app.removeOldRemoteFileLists();
			}
		}
	}
}
